package org.chnxi.study.design.single;

/**
 * 单利模式-懒汉式
 * 在使用的时候，才进行创建对象
 * 问题：
 * 1、不加锁的时候，并发的情况下getInstance会存在对LazySingle创建多个实例
 * 2、使用双重锁检测模式，会保证LazySingle只进行一次实例化，但还需要防止指令重排的情况下发生错误
 */
public class LazySingle implements java.io.Serializable {

    private LazySingle(){
        //对class加锁，主要是防止在已经存在LazySingle实例的情况下，再通过反射机制获取
        synchronized (LazySingle.class){
            if(lazySingle != null){
                throw new RuntimeException("已存在实例对象，禁止再次生成，请通过getInstance方法获取实例");
            }else{
                //将获取到的实例赋值给lazySingle
                lazySingle = this;
            }
        }
    }

    //加入volatile，防止指令重排导致的问题发生
    static volatile LazySingle lazySingle;

    public static LazySingle getInstance(){
        if(lazySingle == null){
            synchronized (LazySingle.class){
                if(lazySingle == null){
                    /**
                     * 问题：
                     * new 操作，不是一个原子操作
                     * （1）分配内存空间 -> （2）执行构造方法 -> （3）把引用指向对象空间
                     * 如果在并发的情况下，发生指令重排，如：1-3-2，虽然分配了空间，但对象还未初始化完成
                     * 需要对lazySingle对象加volatile的修饰
                     */
                    new LazySingle();
                }
            }
        }

        return lazySingle;
    }

}
